2. 컨테이너 살펴보기

1. 가벼운 실습: Ubuntu 22.04 컨테이너 실행

실습 목표

도커를 사용하여 Ubuntu 22.04 이미지를 pull하고 컨테이너로 실행해보기

용어 정리

  • pull: 레지스트리(저장소)에서 이미지를 로컬로 다운로드하는 동작
  • 이미지 (Image): 컨테이너 실행에 필요한 파일과 설정을 담은 읽기 전용 템플릿. 컨테이너의 "설계도"
  • 컨테이너 (Container): 이미지를 기반으로 실행된 프로세스. 이미지의 "실행 인스턴스"

기본 명령어

컨테이너 기본 작업 흐름:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[이미지 다운로드]
    ↓
docker pull ubuntu:22.04
    ↓
[컨테이너 실행]
    ↓
docker run -it ubuntu:22.04
    ↓
[컨테이너 내부에서 작업]

2. 기본적인 컨테이너 기술의 특징

컨테이너 기술의 3대 특징:

컨테이너 핵심 가치:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[컨테이너 기술]
    │
    ├─→ 1. 가벼운 실행 환경
    │      └─ 프로세스 수준 격리
    │      └─ 빠른 시작/종료
    │
    ├─→ 2. 높은 이식성
    │      └─ 동작 재현성
    │      └─ 표준 규격
    │
    └─→ 3. 거대한 생태계
           └─ OCI/CNCF
           └─ 다양한 도구

2.1. 가벼운 실행 환경

가상머신 vs 컨테이너

실행 환경 구조 비교:

[가상머신 (Virtual Machine)]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

┌────────────────────────────┐
│   애플리케이션 + 라이브러리  │
├────────────────────────────┤
│      게스트 OS (Linux)      │
├────────────────────────────┤
│     하이퍼바이저 (KVM)      │
├────────────────────────────┤
│      호스트 OS (Linux)      │
├────────────────────────────┤
│      물리 하드웨어          │
└────────────────────────────┘

특징:
• OS 전체를 가상화
• 부팅 시간: 수십 초~분
• 크기: 수 GB
• 격리: 매우 강력


[컨테이너 (Container)]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

┌────────────────────────────┐
│   애플리케이션 + 라이브러리  │
├────────────────────────────┤
│  컨테이너 런타임 (Docker)   │
├────────────────────────────┤
│      호스트 OS (Linux)      │
│    (네임스페이스 격리)      │
├────────────────────────────┤
│      물리 하드웨어          │
└────────────────────────────┘

특징:
• 프로세스 수준 가상화
• 시작 시간: 수 초 이내
• 크기: 수십 MB~수백 MB
• 격리: OS 커널 공유

가상머신의 동작 원리

하이퍼바이저 기반 가상화:

가상머신은 AWS, Azure 등 대표적인 클라우드 서비스에서 주요 실행 환경으로 제공됨

가상머신 구조:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[물리 서버]
    ↓
[하이퍼바이저]
├─ 가상 하드웨어 제공
├─ 자원 할당 관리
└─ OS 간 격리
    ↓
┌────┬────┬────┐
│VM 1│VM 2│VM 3│
│OS A│OS B│OS C│
└────┴────┴────┘

장점:
✓ 완전한 OS 격리
✓ 다양한 OS 동시 실행
✓ 강력한 보안

단점:
✗ 무거운 리소스 사용
✗ 느린 시작 속도
✗ OS 라이선스 필요

하이퍼바이저 계층의 역할

하이퍼바이저는 하드웨어와 OS 사이에 위치한 관리 계층으로, 가상화의 핵심 역할을 수행함

하이퍼바이저 동작 원리:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[물리 하드웨어]
    │
    ├─ CPU
    ├─ 메모리
    ├─ 디스크
    └─ 네트워크
    ↓
[하이퍼바이저 계층]
    │
    ├─ 하드웨어 추상화
    │  └─ 물리 자원을 가상 자원으로 변환
    │
    ├─ 자원 할당 및 스케줄링
    │  └─ VM별 CPU, 메모리, 디스크 할당
    │
    ├─ VM 격리
    │  └─ VM 간 독립성 보장
    │
    └─ 가상 하드웨어 제공
       └─ 각 VM에게 독립된 하드웨어처럼 보이게 함
    ↓
[게스트 OS들]
    ↓
각 VM은 독립된 물리 머신처럼 동작

핵심:
→ 하이퍼바이저 = 가상화 관리자
→ 하드웨어를 소프트웨어로 에뮬레이션

하이퍼바이저 타입

하이퍼바이저 분류:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[Type 1 - Bare Metal (Native)]
┌────────────────────┐
│   VM 1  │  VM 2    │
├────────────────────┤
│   하이퍼바이저      │
├────────────────────┤
│   물리 하드웨어     │
└────────────────────┘

특징:
• 하드웨어 위에 직접 설치
• 높은 성능
• 서버 가상화에 적합

예시:
├─ VMware ESXi
├─ Microsoft Hyper-V
├─ KVM (Kernel-based Virtual Machine)
└─ Xen


[Type 2 - Hosted]
┌────────────────────┐
│   VM 1  │  VM 2    │
├────────────────────┤
│   하이퍼바이저      │
├────────────────────┤
│   호스트 OS         │
├────────────────────┤
│   물리 하드웨어     │
└────────────────────┘

특징:
• 기존 OS 위에서 실행
• 설치/사용 간편
• 데스크톱 가상화에 적합

예시:
├─ VMware Workstation
├─ Oracle VirtualBox
└─ Parallels Desktop

실무:
→ Type 1: 데이터센터, 클라우드
→ Type 2: 개발자 로컬 환경

활용 사례:


컨테이너의 동작 원리

OS 커널 공유 방식:

컨테이너는 호스트 OS 커널을 기반으로 환경 격리 기능을 활용하여 독립적인 실행 환경을 만듦

OS 커널이란?

OS 커널 (Kernel):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[정의]
운영체제의 핵심 구성 요소로,
하드웨어와 애플리케이션 사이에서
자원을 관리하고 중재하는 계층

[OS 전체 구조]
    ┌──────────────────────┐
    │  애플리케이션 영역    │
    │  (User Space)        │
    ├──────────────────────┤
    │  시스템 라이브러리    │
    │  (libc, glibc 등)    │
    ├──────────────────────┤
    │     커널 영역         │
    │   (Kernel Space)     │
    │  ┌────────────────┐  │
    │  │  프로세스 관리  │  │
    │  │  메모리 관리    │  │
    │  │  파일시스템     │  │
    │  │  네트워크 스택  │  │
    │  │  디바이스 드라이버│ │
    │  └────────────────┘  │
    ├──────────────────────┤
    │   물리 하드웨어       │
    └──────────────────────┘

커널의 주요 역할:
├─ 프로세스 관리
│  └─ 프로세스 생성, 종료, 스케줄링
│
├─ 메모리 관리
│  └─ 메모리 할당, 해제, 가상 메모리
│
├─ 파일시스템 관리
│  └─ 파일 읽기/쓰기, 권한 관리
│
├─ 네트워크 관리
│  └─ 네트워크 통신, 프로토콜 스택
│
└─ 디바이스 관리
   └─ 하드웨어 추상화, 드라이버 인터페이스

핵심:
→ 커널 = OS의 뇌
→ 시스템 자원의 문지기
→ 하드웨어 접근의 중재자

컨테이너가 커널을 공유하는 방식

컨테이너 격리 메커니즘:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[호스트 OS 커널]
    │
    ├─ Namespace (격리)
    │  ├─ PID: 프로세스 격리
    │  ├─ NET: 네트워크 격리
    │  ├─ MNT: 파일시스템 격리
    │  ├─ UTS: 호스트명 격리
    │  └─ IPC: 프로세스 간 통신 격리
    │
    └─ Cgroups (자원 제한)
       ├─ CPU 사용량
       ├─ 메모리 사용량
       └─ 디스크 I/O
    ↓

┌──────────┬──────────┬──────────┐
│컨테이너 1 │컨테이너 2 │컨테이너 3 │
│독립 환경  │독립 환경  │독립 환경  │
└──────────┴──────────┴──────────┘

모든 컨테이너가 동일한 커널 공유
→ 가볍고 빠른 시작
→ 호스트와 동일한 커널 버전 사용

Namespace와 Cgroups 상세

리눅스 커널의 격리 기능:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[Namespace - 격리 기능]
각 컨테이너에게 독립된 환경을 제공

PID Namespace:
├─ 컨테이너마다 독립된 프로세스 ID 공간
├─ 컨테이너 내부: PID 1부터 시작
└─ 다른 컨테이너 프로세스 불가시

NET Namespace:
├─ 독립된 네트워크 인터페이스
├─ 자체 IP 주소, 라우팅 테이블
└─ 포트 충돌 없음

MNT Namespace:
├─ 독립된 파일시스템 마운트
├─ 자체 루트 디렉토리 (/)
└─ 호스트 파일시스템과 분리

UTS Namespace:
├─ 독립된 호스트명
└─ 도메인명 설정

IPC Namespace:
├─ 독립된 프로세스 간 통신
└─ 공유 메모리, 세마포어 격리


[Cgroups - 자원 제한]
컨테이너의 자원 사용을 제한

CPU Cgroup:
└─ 컨테이너당 CPU 사용률 제한
   예: "최대 2 코어만 사용"

Memory Cgroup:
└─ 컨테이너당 메모리 제한
   예: "최대 1GB RAM 사용"

Block I/O Cgroup:
└─ 디스크 읽기/쓰기 속도 제한
   예: "최대 100MB/s"

Network Cgroup:
└─ 네트워크 대역폭 제한

결과:
→ Namespace = "무엇을 볼 수 있는가"
→ Cgroups = "얼마나 사용할 수 있는가"

컨테이너 격리 특징

컨테이너의 격리 수준:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[컨테이너 내부에서 보는 세계]
    │
    ├─ 독립된 루트 파일시스템
    │  └─ /bin, /etc, /lib 등
    │
    ├─ 격리된 프로세스 공간
    │  └─ 다른 컨테이너 프로세스 불가시
    │
    ├─ 독립된 네트워크
    │  └─ 자체 IP, 포트
    │
    └─ 호스트 자원 제한
       └─ CPU, 메모리 제한

핵심:
→ OS 커널 포함 X
→ 프로세스로 실행
→ 마치 독립 OS처럼 동작

가상머신 vs 컨테이너 비교

구분 가상머신 컨테이너
가상화 대상 하드웨어 OS 커널
OS 게스트 OS 포함 호스트 OS 공유
시작 속도 느림 (분) 빠름 (초)
크기 큰 편 (GB) 작음 (MB)
자원 사용 많음 적음
격리 수준 강력 중간
이식성 보통 높음
용도 완전한 OS 환경 필요 애플리케이션 배포

2.2. 높은 이식성

컨테이너 이미지의 동작 재현성

이식성의 핵심 원리:

컨테이너 이미지 이식성:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[개발 환경]
    ↓
[컨테이너 이미지 빌드]
├─ 애플리케이션 코드
├─ 의존 라이브러리
├─ 런타임 환경
└─ 설정 파일
    ↓
[이미지를 레지스트리에 푸시]
    ↓
[다른 환경에서 Pull]
    ↓
┌────────┬────────┬────────┐
│개발 PC │테스트  │프로덕션│
│환경    │서버    │서버    │
└────────┴────────┴────────┘
    ↓
동일한 동작 보장

장점:
✓ "내 컴퓨터에서는 되는데..." 문제 해결
✓ 환경 차이로 인한 버그 최소화
✓ 빠른 배포

라이브러리 버전 불일치 해결

전통적 배포 방식의 문제:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[개발 환경]
Python 3.9
Django 4.0
PostgreSQL 13
    ↓
[프로덕션 서버]
Python 3.8  ← 버전 차이!
Django 3.2  ← 호환성 문제!
PostgreSQL 12
    ↓
[애플리케이션 오류]


컨테이너 방식:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[컨테이너 이미지]
├─ Python 3.9
├─ Django 4.0
├─ PostgreSQL 13
└─ 모든 의존성 포함
    ↓
[어디서나 동일하게 실행]
    ↓
환경 불일치 문제 해결

업계 표준 규격

컨테이너 표준 작업 흐름:

컨테이너 작업 흐름:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

1. Build (빌드)
   └─ Dockerfile로 이미지 생성
        ↓

2. Ship (공유)
   └─ 레지스트리에 이미지 푸시
        ↓

3. Run (실행)
   └─ 컨테이너 런타임으로 실행

이 세 단계가 표준화됨

컨테이너 기술 스택

컨테이너 표준 기술 스택:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[빌드 도구]
├─ Docker Build
├─ Buildah
└─ Kaniko

[레지스트리]
├─ Docker Hub
├─ AWS ECR
├─ Google GCR
└─ Harbor

[컨테이너 런타임]
├─ Docker Engine
├─ containerd
├─ CRI-O
└─ Podman

모두 OCI 표준 준수
→ 상호 호환 가능

2.3. 거대한 생태계

Open Container Initiative (OCI)

용어 정리

  • OCI (Open Container Initiative): 2015년 Docker, CoreOS, Google 등이 설립한 오픈소스 프로젝트. 컨테이너 기술의 표준 규격을 정의하여 벤더 종속성을 방지
  • Spec (Specification): 규격/명세서. 소프트웨어가 따라야 하는 표준 정의 문서

OCI의 역할:

OCI (Open Container Initiative):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[리눅스 재단 산하]
    ↓
[OCI 프로젝트]
    │
    ├─→ 이미지 규격 (Image Spec)
    │   └─ 컨테이너 이미지 형식 정의
    │
    ├─→ 런타임 규격 (Runtime Spec)
    │   └─ 컨테이너 실행 방법 정의
    │
    └─→ 배포 규격 (Distribution Spec)
        └─ 레지스트리 동작 방식 정의

결과:
→ 다양한 도구 간 상호 운용성
→ 벤더 종속성 감소
→ 생태계 확장

Cloud Native Computing Foundation (CNCF)

용어 정리

  • CNCF (Cloud Native Computing Foundation): 클라우드 네이티브 오픈소스 프로젝트를 관리하는 Linux Foundation 산하 재단. Kubernetes, Prometheus, Envoy 등을 관리
  • Cloud Native: 클라우드 환경에 최적화된 애플리케이션 개발/운영 방식. 컨테이너, 마이크로서비스, CI/CD, 오케스트레이션 등을 활용
  • Graduated/Incubating/Sandbox: CNCF 프로젝트 성숙도 등급. Sandbox(초기) → Incubating(성장) → Graduated(성숙)

CNCF 프로젝트 성숙도:

CNCF 프로젝트 단계:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[Graduated - 졸업]
├─ Kubernetes
├─ Prometheus
├─ Envoy
├─ containerd
└─ Helm
    ↓
가장 성숙하고 널리 사용됨
프로덕션 환경 권장

[Incubating - 인큐베이팅]
├─ etcd
├─ CoreDNS
└─ Argo
    ↓
안정화 단계
활발히 개발 중

[Sandbox - 샌드박스]
└─ 초기 단계 프로젝트
    ↓
실험적 기술

쿠버네티스 관련 표준

용어 정리:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[Interface (인터페이스)]
    │
    └─ 서로 다른 시스템이 소통하는 방식을 정의한 규약
       "이 규칙만 따르면 어떤 구현체든 연결 가능"

[플러그인 (Plugin)]
    │
    └─ 기본 시스템에 기능을 추가하는 확장 모듈
       표준 인터페이스를 따르면 쉽게 교체 가능

[deprecated]
    │
    └─ 더 이상 권장되지 않음, 향후 제거 예정
       새 프로젝트에서는 사용 자제
쿠버네티스 플러그인 인터페이스:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[CRI - Container Runtime Interface]
└─ 컨테이너 런타임 플러그인
   ├─ containerd
   ├─ CRI-O
   └─ Docker (deprecated)

[CSI - Container Storage Interface]
└─ 스토리지 플러그인
   ├─ AWS EBS
   ├─ Ceph
   └─ NFS

[CNI - Container Network Interface]
└─ 네트워크 플러그인
   ├─ Calico
   ├─ Flannel
   └─ Cilium

표준화된 인터페이스
→ 다양한 구현체
→ 선택의 자유

3. 이 책에서 다루는 도커와 쿠버네티스

도커 (Docker)

도커의 역할:

도커 기능:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[단일 머신 컨테이너 관리]
    │
    ├─→ 컨테이너 실행/중지
    │   └─ docker run, docker stop
    │
    ├─→ 이미지 빌드
    │   └─ Dockerfile 기반 빌드
    │
    ├─→ 이미지 공유
    │   └─ Docker Hub, Registry
    │
    └─→ 네트워크/볼륨 관리
        └─ 로컬 개발 환경

핵심 가치:
→ 컨테이너 기술 대중화
→ 간단한 작업 흐름 제공
→ 개발자 친화적

도커의 영향

도커는 도구 자체의 편의성뿐만 아니라 컨테이너 기본 조작을 간단한 작업 흐름(Build, Ship, Run)으로 업계에 전파하여 컨테이너 기술 확산에 큰 역할을 함


쿠버네티스 (Kubernetes)

쿠버네티스의 역할:

쿠버네티스 기능:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[다중 머신 컨테이너 오케스트레이션]
    │
    ├─→ 자가 치유 (Self-Healing)
    │   └─ 노드 장애 시 자동 재시작
    │
    ├─→ 오토 스케일링
    │   └─ 부하에 따라 자동 확장/축소
    │
    ├─→ 로드 밸런싱
    │   └─ 트래픽 분산
    │
    ├─→ 롤링 업데이트
    │   └─ 무중단 배포
    │
    └─→ 선언적 관리
        └─ 매니페스트 기반 인프라 관리

대상:
→ 프로덕션 환경
→ 대규모 시스템

선언적 관리 스타일

쿠버네티스 선언적 관리:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[매니페스트 작성 (YAML)]
    ↓
원하는 상태 정의:
"이 애플리케이션은
3개의 복제본으로 실행되어야 함"
    ↓
[kubectl apply]
    ↓
[쿠버네티스가 자동으로 현재 상태를 원하는 상태로 조정]
    ↓
┌────────┬────────┬────────┐
│ Pod 1  │ Pod 2  │ Pod 3  │
└────────┴────────┴────────┘

장점:
✓ 인프라를 코드로 관리
✓ 버전 관리 가능
✓ 재현 가능
✓ 자동화

명령형 vs 선언형 비교

관리 방식 비교:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[명령형 (Imperative)]
"컨테이너 3개를 시작해"
"컨테이너 1개를 중지해"
"포트 80을 열어"
    ↓
단계별 명령 실행
    ↓
✗ 복잡한 조작 필요
✗ 현재 상태 파악 어려움


[선언형 (Declarative)]
"최종 상태는 이것이다"
replicas: 3
port: 80
    ↓
쿠버네티스가 알아서 조정
    ↓
✓ 단순한 관리
✓ 자가 치유
✓ GitOps 가능

컨테이너 런타임

컨테이너 런타임의 역할

컨테이너 런타임:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[정의]
관리 도구의 지시를 받아
머신에서 컨테이너를 직접 작성하고
관리하는 저수준 소프트웨어

[역할]
    ↓
[도커/쿠버네티스]
    │ 명령
    ↓
[컨테이너 런타임]
├─ Namespace 생성
├─ Cgroups 설정
├─ 파일시스템 마운트
└─ 프로세스 실행
    ↓
[컨테이너 프로세스]

숨은 실력자:
→ 컨테이너를 컨테이너답게 만드는 핵심

컨테이너 런타임 계층

컨테이너 런타임 구조:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[High-level Runtime]
├─ Docker Engine
├─ containerd
└─ CRI-O
    │
    ↓ OCI 표준 호출
    │
[Low-level Runtime]
└─ runc (OCI 참조 구현)
    │
    ↓
[Linux Kernel]
├─ Namespace
├─ Cgroups
└─ Capabilities

도커와 쿠버네티스의 런타임 사용

런타임 사용 관계:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[도커]
    ↓
[Docker Engine]
    ↓
[containerd]
    ↓
[runc]


[쿠버네티스]
    ↓
[CRI 플러그인]
    ↓
[containerd / CRI-O]
    ↓
[runc]

쿠버네티스 자체는
컨테이너 생성 기능 없음
→ 각 노드의 런타임이 담당

핵심 요약

컨테이너 기술 요약:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[컨테이너]
├─ 가벼운 실행 환경
│  └─ OS 커널 공유, 프로세스 격리
│
├─ 높은 이식성
│  └─ 이미지 기반 배포, 표준 규격
│
└─ 거대한 생태계
   └─ OCI, CNCF, 다양한 도구

[도커]
└─ 단일 머신 컨테이너 관리
   └─ Build, Ship, Run

[쿠버네티스]
└─ 다중 머신 오케스트레이션
   └─ 자동화, 확장성, 고가용성

[컨테이너 런타임]
└─ 실제 컨테이너 실행
   └─ runc, containerd, CRI-O

결론:
→ 컨테이너 = 현대 애플리케이션 배포 표준
→ 도커 = 개발 및 로컬 환경
→ 쿠버네티스 = 프로덕션 환경

참고 자료

공식 문서:

관련 주제: